0xk4k45h1
Active Directory
Domain Enumeration
Kerberoast
Kerberos Delegation
LLMNR poisoning
SMB relay
CTF
0xL4ugh 2024
Arab Cyber War Games Qualifications 2024
CyCTF qualification 2024
ICMTC Qualification 2024
IEEE Victoris 2024
PortSwigger
Wani CTF 2024
HackTheBox
Machines
Devvortex
Drive
Editorial
Intuition
PC
Visual
Sherlock
Mobile Pentesting
Android
Android Basics
Android Dynamic Analysis
Android Static Analysis
Home
Contact
Copyright © 2024 |
Yankos
Home
>
CTF
> IEEE Victoris 2024
Now Loading ...
IEEE Victoris 2024
Web: Slippery Way (Medium)
Solution When we get the files of the challenge we will see this file hierarchy. and this is app.py from flask import Flask, render_template, request, redirect, url_for, session, send_from_directory import os import random import string import time import tarfile from werkzeug.utils import secure_filename app = Flask(__name__) app.secret_key = "V3eRy$3c43T" def otp_generator(): otp = ''.join(random.choices(string.digits, k=4)) return otp if not os.path.exists('uploads'): os.makedirs('uploads') @app.route('/', methods=['GET', 'POST']) def main(): if 'username' not in session or 'valid_otp' not in session: return redirect(url_for('login')) if request.method == 'POST': uploaded_file = request.files['file'] if uploaded_file.filename != '': filename = secure_filename(uploaded_file.filename) file_path = os.path.join('uploads', filename) uploaded_file.save(file_path) session['file_path'] = file_path return redirect(url_for('extract')) else: return render_template('index.html', message='No file selected') return render_template('index.html', message='') @app.route('/extract') def extract(): if 'file_path' not in session: return redirect(url_for('login')) file_path = session['file_path'] output_dir = 'uploads' if not tarfile.is_tarfile(file_path): os.remove(file_path) return render_template('extract.html', message='The uploaded file is not a valid tar archive') with tarfile.open(file_path, 'r') as tar_ref: tar_ref.extractall(output_dir) os.remove(file_path) return render_template('extract.html', files=os.listdir(output_dir)) @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] if username == 'admin' and password == 'admin': session['username'] = username return redirect(url_for('otp')) else: return render_template('login.html', message='Invalid username or password') return render_template('login.html', message='') @app.route('/otp', methods=['GET', 'POST']) def otp(): if 'username' not in session: return redirect(url_for('login')) if request.method == 'POST': otp,_otp = otp_generator(),request.form['otp'] if otp in _otp: session['valid_otp'] = True return redirect(url_for('main')) else: time.sleep(10) # please don't bruteforce my OTP return render_template('otp.html', message='Invalid OTP') return render_template('otp.html', message='') @app.route('/logout') def logout(): session.pop('username', None) session.pop('valid_otp', None) session.pop('file_path', None) return redirect(url_for('login')) @app.route('/uploads/<path:filename>') def uploaded_file(filename): uploads_path = os.path.join(app.root_path, 'uploads') return send_from_directory(uploads_path, filename) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) When we start the challenge we see this login page from the code we will login using admin:admin and we will get forwarded to /otp endpoint We can’t go to anyother endpoint without submiting the valid otp. Trying to brute force or bypass this page through the otp form is a rabbit hole. When we look in the source code we will find interesting things. Each user of course have a cookie This is Flask application which moves us to think about flask-unsign cookie flask-unsign cookie is something like JWT that needs a secret signing key to forge a cookie We already have this secret app.secret_key = "V3eRy$3c43T" when we decode the cookie we will find this {"username": "admin"} from the code that if the otp is validated, then session['valid_otp'] = True So we need to forge a new cookie with username and valid_otp keys we will use flask-unsign ┌──(youssif㉿youssif)-[~] └─$ flask-unsign --sign --cookie "{'username': 'admin','valid_otp': True}" --secret 'V3eRy$3c43T' eyJ1c2VybmFtZSI6ImFkbWluIiwidmFsaWRfb3RwIjp0cnVlfQ.Zvau5g.TioGBeLlSjBfw2V2CwACLyp9MpM When we use the new cookie we can access the other endpoints Now visit / again and you will find this upload page When we go back to upload function in our code we will find that it accepts only tar file And in /extract this uploaded tar got extracted After searching i found this candy From this article we knew that we can get LFI from tar upload function using ┌──(youssif㉿youssif)-[~] └─$ ln -s ../../../../../../../../../etc/passwd kakashi.txt tar -cvf test.tar kakashi.txt We created a symbolic link from kakashi.txt to ../../../../../../../../../etc/passwd Then we put it in the tar file. We will upload the file and when we go to /extract it will give us kakashi.txt open this file and GG you got /etc/passwd you can read the flag as the flag path was leaked in init.sh file. Congratzzzzzzzzzzzzzzz
CTF
· 2024-09-27
Web: Coco Elda3eef Revenge (Easy) -- My First Blood --
Solution This challenge is the hard version of coco elda3eef. When we get the files of the challenge we will see this file hierarchy and it’s exactly the same like coco elda3eef easy challenge. We have a web server running by nodeJS and there’s an nginx proxy between the client and the server The server.js code is very simple and the same as the previous challenge. const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.sendfile('index.html'); }); app.get('/internal', (req, res) => { resp = process.env.FLAG || "IEEE{test_flag}" res.send(resp); }); app.listen(port, () => { console.log(`App listening on port ${port}`); }); It’s running on port 3000, and to get the flag you need to visit /internal endpoint. But when we look at nginx.conf and here is the difference worker_processes 1; events { worker_connections 1024; } http { server { listen 80; location ~* ^/internal$ { allow 127.0.0.1; deny all; return 403; } location ~* ^/internal/ { allow 127.0.0.1; deny all; return 403; } location / { proxy_pass http://ghazy-corp:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } } from the code of the proxy we see that if we visit /internal directly we will get 403 forbidden status code. But this can’t be bypassed like the previous challenge because of this so we can’t use /InTernal to bypass it. After searching i found this candy The interesting part is here we have characters that nginx can see it but nodeJS removes it. so we can append this character to /internal so bypassing the nginx rule and it this appended character will be removed by nodeJS resulting in visiting `/internal and getting the flag from the blog we need the character whose hex is A0 so we will change the hex of the appended character to A0. Let’s apply changes and send the request And Congratzzzzzzzzzzzz.
CTF
· 2024-09-27
Web: Coco Elda3eef (Easy)
Solution When we get the files of the challenge we will see this file hierarchy. We have a web server running by nodeJS and there’s an nginx proxy between the client and the server The server.js code is very simple const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.sendfile('index.html'); }); app.get('/internal', (req, res) => { resp = process.env.FLAG || "IEEE{test_flag}" res.send(resp); }); app.listen(port, () => { console.log(`App listening on port ${port}`); }); It’s running on port 3000, and to get the flag you need to visit /internal endpoint. But when we look at nginx.conf worker_processes 1; events { worker_connections 1024; } http { server { listen 80; location = /internal { allow 127.0.0.1; deny all; return 403; } location = /internal/ { allow 127.0.0.1; deny all; return 403; } location / { proxy_pass http://ghazy-corp:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } } from the code of the proxy we see that if we visit /internal directly we will get 403 forbidden status code. This can be bypassed easily by visiting /InTernal as example (change the case of any character) And Congratzzzzzzzzzzzz.
CTF
· 2024-09-27
<
>
Touch background to close